// Copyright 2007 Helsinki Institute for Information Technology
// and the authors.
//
// Authors: Petri Savolainen <petri.savolainen@hiit.fi>

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation files
// (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

function Vector(initialData)
	{
	var self = this;
	
	
	var elementCount = 0;
	var capacityIncrement = 0;
	var elementData = null;
	
	if (initialData)
		{
		elementData = initialData;
		elementCount = elementData.length;
		}
	else	
		elementData = new Array(10);
	
	this.getBytes = function()
		{
		return elementData;
		}
	
	this.setBytes = function(b)
		{
		elementData = b;
		elementCount = b.length;
		}
	
	this.subarray = function(begin, end)
		{
		var ret= new Array(end-begin);
	
		var j=0;
		for (var i=begin; i<end; i++)
			{
			ret[j]=elementData[i];
			j++;
			}
		return ret;	
		}
		
	this.subvector = function(begin, end)
		{
		return new Vector(self.subarray(begin,end));
		}
	
	this.subvectorUntil = function(begin, marker)
		{
		for (var i=begin; i<elementCount; i++)
			{
			if (elementData[i]==marker)
				{
				return self.subvector(begin,i);
				}
			}
		return null;	
		}
	
	this.ensureCapacity = function(minCapacity)
		{
		if (elementData.length >= minCapacity)
       			return;

		var newCapacity;
     		if (capacityIncrement <= 0)
			newCapacity = elementData.length * 2;
		else
			newCapacity = elementData.length + capacityIncrement;
	

     		var newArray = new Array(newCapacity > minCapacity ? newCapacity : minCapacity);

     		for (var i=0; i<elementCount; i++)
			{
			newArray[i]= elementData[i];
     			}
		
		elementData = newArray;
		}	

	
	this.add = function(obj)
		{
		if (elementCount == elementData.length)
       			self.ensureCapacity(elementCount + 1);
     	
		elementData[elementCount] = obj;
		elementCount++;
		}
	
	this.get = function(index)
		{
		return elementData[index];
		}
	
	this.set = function(index,dat)
		{
		elementData[index] = dat;
		}
	
	this.insert = function(index,dat)
		{
		if (elementCount == elementData.length)
       			self.ensureCapacity(elementCount + 1);
     	
		for (var i=elementCount; i>index; i--)
			{
			elementData[i] = elementData[i-1];			
			}
		elementData[index] = dat;
		elementCount++;				
		}
	
	this.size = function()
		{
		return elementCount;
		}
		
	this.clear = function()
		{
		for (var i=0; i<elementCount; i++)
			elementData[i] = null;
		elementCount = 0;
		}
		
	this.toNumericString = function()
		{
		var ret = '[';
		for (var i=0; i<elementCount; i++)
			{
			ret+= elementData[i];
			if (i<(elementCount-1))
				ret+=',';
			}
		ret+=']';	
		return ret;
		}
	this.toString = function()
		{
		var ret = '';
		for (var i=0; i<elementCount; i++)
			{
			if (elementData[i]!=0)
				ret+=String.fromCharCode(elementData[i]);
			}
		return ret;
		}
		
	this.appendByte = function(b)
		{
		self.add(b);
		}		
		
	this.appendLong = function(l)
		{
		self.add( (l>>24)  & 0xff);
		self.add( (l>>16)  & 0xff);
		self.add( (l>>8)  & 0xff);
		self.add(l & 0xff);
		}		
		
	this.appendArray = function(arr)
		{
		for (var i=0; i<arr.length; i++)
			{
			self.add(arr[i]);
			}
		}		
		
	this.appendString = function(str)
		{
		for (var i=0; i<str.length; i++)
			{
			self.add(str.charCodeAt(i));
			}
		}
	this.extractLong = function(index)
		{
		var ret = 0;
		var temp = 0;
		temp = elementData[index];
		ret = ret | temp; 
		ret *= 256;
		temp = elementData[index+1];
		ret=ret | temp;
		ret *= 256;
		temp = elementData[index+2];
		ret=ret | temp;
		ret *= 256;
		temp = elementData[index+3];
		ret = ret | temp;
		
		return ret;
		}	
	
	this.removeFromBeginning = function(amount)
		{
		if (amount>=elementCount)
			self.clear();
		else
			{
			var j=0;
			for (var i=amount; i<elementCount; i++)
				{
				elementData[j] = elementData[i];
				j++;
				}
			elementCount = j;
			//dump('\nRemoved from beginning '+amount+ ' bytes left is '+this.toNumericString());
			}
		
		}	
	
	this.removeElementAt = function(index)
		{
		elementData[i] = null;
		//delete elementData[i];
		for (var i= index; i< (elementCount-1); i++)
			{
			elementData[i] = elementData[i+1];
			}
		elementCount -= 1;
		}
		
	this.removeElement = function(element)
		{
		var index = -1;
		for (var i=0; i<elementCount; i++)
			{
			if (elementData[i].equals(element))
				index=i;
			}
		if (index != -1)
			self.removeElementAt(index);
		
		}
		
	this.truncateTo = function(siz)	
		{
		if (elementCount > siz)
			elementCount = siz;
		}
		
	this.contains = function(item)
		{
		for (var i=0; i<elementCount; i++)
			{
			if (item.equals(elementData[i]))
				return true;
			}
		return false;
		}	
		
	this.indexOf = function(item)
		{
		for (var i=0; i<elementCount; i++)
			{
			if (item.equals(elementData[i]))
				return i;
			}
		return -1;
		}		
	}
